<?php
declare (strict_types=1);

namespace app\admin\controller\iot;

use app\admin\model\iot\Device;
use app\admin\model\iot\ScanBagWayDevice;
use app\admin\service\iot\DeviceService;
use app\BaseController;
use app\datacenter\model\Machine;
use ciphertext\RsaIotData;
use emqx\EmqxMqttClient;
use iot\DeviceClient;
use think\App;
use think\facade\Db;
use think\facade\Log;
use think\facade\Request;
use think\response\Json;

/**
 * 设备系统v2和v1信息同步
 */
class DeviceSyn extends BaseController
{
    /**
     * 客户端唯一ID
     * @var string|mixed
     */
    public string $imei = '';
    public string $appSecret = 'e1ea3cf8ca2e6ec8a11c7a5d268f65b0';

    /**
     * 测试生成Code
     * @return void
     */
    private function generationCodeTest()
    {
        $temp['imei'] = '86938305740684501230';
        $temp['nonce'] = uuid();
        $temp['time'] = time();
        $temp['sign'] = secureSignature($temp, $this->appSecret);
        $code = RsaIotData::publicEncrypt(json_encode($temp));
        halt($code);
    }

    /**
     * Apk接口鉴权
     * @return bool
     */
    private function apkVerify(): bool
    {
        //验证code鉴权参数
        $code = request()->param('code/s', '');
        if (!$code) return false;
        //利用私钥解码
        $code_data = RsaIotData::privateDecrypt($code);
        if (!$code_data) return false;
        //验证参数
        $code_data = json_decode($code_data, true);
        //验证时间
        if ($code_data['time'] <= (time() - 300)) {
            return false;
        }
        //验证签名
        $sign = $code_data['sign'];
        unset($code_data['sign']);
        $verify_sign = secureSignature($code_data, $this->appSecret);
        if ($verify_sign != $sign) {
            return false;
        }
        //赋值
        $this->imei = $code_data['imei'];
        return true;
    }

    /**
     * 设备注册
     * @return Json
     */
    public function deviceRegister(): Json
    {
        if (!$this->apkVerify()) {
            return jsonReturn(0, [], 'Code验证错误');
        }
        //接受设备上传的参数
        $params['type'] = Request::param('type/d', 0);
        $params['ip'] = Request::param('ip/s', '');
        $params['sim'] = Request::param('sim/s', '');
        $params['apk'] = Request::param('apk/s', '');
        $params['firmware'] = Request::param('firmware/s', '');

        //开始2023-1-10
        //新增真实的设备6610002换成6610551（虚拟的）
        $update_mac = [
            6610463,
            6610462,
            6610249,
            6610247,
            6610239,
            6610238,
            6610210,
            6610187,
            6610186,
            6610185,
            6610184,
            6610183,
            6610181,
            6610177,
            6610176,
            6610175,
            6610174,
            6610173,
            6610172,
            6610171,
            6610170,
            6610169,
            6610168,
            6610167,
            6610165,
            6610164,
            6610163,
            6610162,
            6610161,
            6610160,
            6610159,
            6610158,
            6610157,
            6610156,
            6610155,
            6610154,
            6610153,
            6610151,
            6610150,
            6610149,
            6610146,
            6610144,
            6610142,
            6610141,
            6610132,
            6610129,
            6610128,
            6610127,
            6610126,
            6610125,
            6610124,
            6610123,
            6610122,
            6610121,
            6610120,
            6610119,
            6610118,
            6610117,
            6610116,
            6610113,
            6610112,
            6610111,
            6610110,
            6610109,
            6610108,
            6610107,
            6610106,
            6610105,
            6610103,
            6610065,
            6610064,
            6610063,
            6610062,
            6610061,
            6610060,
            6610059,
            6610058,
            6610056,
            6610055,
            6610054,
            6610053,
            6610052,
            6610051,
            6610050,
            6610049,
            6610048,
            6610047,
            6610046,
            6610045,
            6610042,
            6610041,
            6610040,
            6610039,
            6610038,
            6610037,
            6610036,
            6610035,
            6610034,
            6610033,
            6610032,
            6610030,
            6610028,
            6610027,
            6610026,
            6610025,
            6610024,
            6610023,
            6610022,
            6610021,
            6610020,
            6610019,
            6610018,
            6610016,
            6610015,
            6610014,
            6610013,
            6610012,
            6610011,
            6610010,
            6610008,
            6610007,
            6610006,
            6610005,
            6610004,
            6610003,
            6610001,
            82271,
            81138,
            81666,
            81133,
            82289,
            82287,
            82286,
            82285,
            82270,
            82268,
            82267,
            82266,
            82265,
            82264,
            82263,
            82262,
            82261,
            82260,
            82259,
            82258,
            82257,
            82254,
            82253,
            82248,
            82247,
            82246,
            82245,
            82244,
            82243,
            82242,
            82241,
            82237,
            82235,
            82234,
            82233,
            82228,
            82219,
            82218,
            82217,
            82216,
            82207,
            82206,
            82205,
            82204,
            82203,
            82202,
            82201,
            82200,
            82199,
            82198,
            82195,
            82182,
            82181,
            82180,
            82179,
            81369,
            81367,
            81366,
            81345,
            81120,
            81116,
            81115,
            81114,
            81110,
            81092,
            81086,
            81085,
            80955,
            80954,
            80951,
            80950,
            82238,
            6610212,
            6610208,
            6610207,
            6610206,
            6610204,
            6610203,
            6610202,
            6610201,
            6610199,
            6610198,
            6610197,
            6610196,
            6610195,
            6610194,
            6610193,
            6610192,
            6610191,
            6610190,
            6610189,
            6610182,
            6610180,
            6610179,
            6610178,
            6610075
        ];
        //需要改的虚拟设备
        $update_mac_x = [
            6610616,
            6610615,
            6610614,
            6610574,
            6610573,
            6610572,
            6610561,
            6610560,
            6610559,
            6610558,
            6610557,
            6610556,
            6610555,
            6610554,
            6610553,
            6610552,
            6610550,
            6610549,
            6610548,
            6610547,
            6610546,
            6610545,
            6610544,
            6610543,
            6610542,
            6610541,
            6610540,
            6610539,
            6610538,
            6610537,
            6610536,
            6610535,
            6610534,
            6610533,
            6610532,
            6610531,
            6610530,
            6610529,
            6610528,
            6610527,
            6610526,
            6610525,
            6610524,
            6610523,
            6610522,
            6610521,
            6610520,
            6610519,
            6610518,
            6610517,
            6610516,
            6610515,
            6610514,
            6610513,
            6610512,
            6610511,
            6610510,
            6610509,
            6610508,
            6610507,
            6610506,
            6610505,
            6610504,
            6610503,
            6610502,
            6610501,
            6610500,
            6610499,
            6610498,
            6610497,
            6610496,
            6610495,
            6610494,
            6610493,
            6610440,
            6610439,
            6610437,
            6610435,
            6410144,
            6410143,
            6410142,
            6410135,
            6410133,
            6410132,
            6410129,
            6410125,
            6410115,
            6410114,
            6410072,
            6410071,
            6410070,
            6410069,
            6410068,
            6410067,
            6410066,
            6410065,
            6410064,
            6410063,
            6410042,
            6410041,
            6410040,
            6410039,
            6410038,
            6410037,
            6410036,
            6410035,
            6410034,
            6410033,
            6410032,
            6410031,
            6410030,
            6410029,
            6410028,
            6410027,
            6410026,
            6410025,
            6410024,
            6410023,
            6410022,
            6410021,
            6410020,
            6410019,
            6410018,
            6410017,
            6410016,
            6410015,
            6410014,
            6410081,
            6410080,
            6410079,
            6410078,
            6410077,
            6410076,
            6410075,
            6410074,
            6410073,
            6410062,
            6410061,
            6410060,
            6410059,
            6410058,
            6410057,
            6410056,
            6410055,
            6410054,
            6410053,
            6410171,
            6410165,
            6410164,
            6410163,
            6410162,
            6410161,
            6410103,
            6410102,
            6410101,
            6410100,
            6410099,
            6410098,
            6410096,
            6410095,
            6410094,
            6410093,
            6410092,
            6410091,
            6410090,
            6410089,
            6410088,
            6410087,
            6410086,
            6410085,
            6410084,
            6610427,
            6610464,
            6610466,
            6610467,
            6610476,
            6610478,
            6610480,
            6610483,
            6610485,
            6610486,
            6610488,
            6610489,
            6610490,
            6610563,
            6610564,
            6610565,
            6610567,
            6610569,
            6610604,
            6610605,
            6610607,
            6610608,
            6610609,
            6610611,
            6610613,
            6610426,
            6410082,
            6610428,
            6610465,
            6610468,
            6610469,
            6610470,
            6610471,
            6610472,
            6610473,
            6610474,
            6610475,
            6610477,
            6610479,
            6610481,
            6610482,
            6610484,
            6610487,
            6610491,
            6610566,
            6610568,
            6610570,
            6610571,
            6610606,
            6610610,
            6610612
        ];


        //查询需要被改的真实数据
        $update_data_list = Db::connect('iot')
            ->table('machine_stock')
            ->whereIn('serial',$update_mac)
            ->select()->toArray();
        $update_data_list_ids = array_column($update_data_list,'serial','secret');


        //查询需要被改的真实数据
        $update_data_list_x = Db::connect('iot')
            ->table('machine_stock')
            ->whereIn('serial',$update_mac_x)
            ->select()->toArray();
        $update_data_list_x_ids = array_column($update_data_list_x,'secret','serial');
        if(isset($update_data_list_ids[$this->imei])){
            //替换设备信息
            $key = false;
            foreach ($update_mac as $k=>$item){
                if($item == $update_data_list_ids[$this->imei]){
                    $key = $k;
                    break;
                }
            }
            if($key !== false && isset($update_data_list_x_ids[$update_mac_x[$key]])){
                $this->imei = $update_data_list_x_ids[$update_mac_x[$key]];
            }
        }
        //固定设备，真实的设备6610002换成6610551（虚拟的）
        if($this->imei == '869383057408643') $this->imei = '869381111111458';
        //结束2023-1-10


        //设备注册设备表
        $params['imei'] = $imei = $this->imei;
        //查找设备之前是否已安装到V1
        $machine = Machine::getMacId($params['imei']);
        if($machine){
            //指定取袋路径
            //删除当前设备
            $scan_bag_way = ScanBagWayDevice::where('mac_id',$machine['serial'])->find();
            $data[]=[
                'key'=>'V2_Way_2_0',
                'mac_id'=>$machine['serial'],
                'remark'=>$machine['serial'],
                'update_time'=>time()
            ];
            if($scan_bag_way){
                if(preg_match('/^V1_*/',$scan_bag_way->key,$result)){
                    ScanBagWayDevice::deleteData(['mac_id' => $machine['serial']], true);
                    $model = new ScanBagWayDevice();
                    $model->saveAll(array_merge($data));
                }
            }else{
                $model = new ScanBagWayDevice();
                $model->saveAll(array_merge($data));
            }
        }
        $device = Device::deviceRegister($params);
        if (!$device) {
            return jsonReturn(0, [], '设备信息错误');
        }
        //默认未安装
        $device_data['install'] = 0;
        $device_data['mac_id'] = $device['mac_id'];
        //设备注册写入V1工单系统
        try {
            $body_data = [
                'mac_id' => $device['mac_id'],
                'version' => $device['apk'],
                'thirdparty_mac_id' => $device['imei'],
                'equipment_type' => $device['type'],
            ];
            $sign = arrayDataSignature($body_data);
            $body_data['sign'] = $sign;
            $params_ready = [
                'form_params' => $body_data
            ];
            $bind_machine_url = config('sys_config.WsScanBag.v1_iot_pay_uri') . '/api/machine/bindMachine';
            $result = httpPost($bind_machine_url, $params_ready);
            $content = json_decode($result['content'], true);
            //更新设备状态
            if ($result['status_code'] == 200 && $content['code'] == 200) {
                $device_data['mac_id'] = $content['data']['mac_id'] ?? $device['mac_id'];
                $device_data['install'] = $content['data']['is_register'] == 1 ? 1 : 0;
                $device_data['latitude'] = $content['data']['latitude'] ?? '';
                $device_data['longitude'] = $content['data']['longitude'] ?? '';
                $device_data['province'] = $content['data']['province'] ?? 0;
                $device_data['city'] = $content['data']['city'] ?? 0;
                $device_data['county'] = $content['data']['county'] ?? 0;
                $device_data['addr'] = $content['data']['addr'] ?? '';
                Device::update($device_data, ['imei' => $imei]);
            } else {
                return jsonReturn(0, [], '设备信息错误');
            }
        } catch (\Exception $exception) {
            Log::write($exception->getLine(), '设备注册V1工单系统');
            Log::write($exception->getMessage(), '设备注册V1工单系统');
            return jsonReturn(0, [], '设备注册V1工单系统错误');
        }
        //需要连接MQTT的参数
        $Emqx = new EmqxMqttClient();
        $mqtt['mqtt_host'] = $Emqx->emqx_mqtt_host;
        $mqtt['mqtt_port'] = $Emqx->emqx_mqtt_port;
        $mqtt['username'] = $imei;
        $mqtt['password'] = $Emqx->emqx_mqtt_device_password;
        $mqtt['topic_php'] = $Emqx->emqx_mqtt_device_topic;
        $mqtt['topic_apk'] = $imei;
        $mqtt = RsaIotData::privateEncrypt(json_encode($mqtt));
        //设备信息
        $client['mac_id'] = strval($device_data['mac_id']);
        $client['install'] = $device_data['install'];
        //获取聚合码地址
        $client['takebag_uri'] = env('ApiDomainV2');
        $client['takebag_qrcode'] = $client['takebag_uri'] . '?mac_id=' . $client['mac_id'];
        //返回信息
        return jsonReturn(1, ['mqtt' => $mqtt, 'client' => $client]);
    }

    /**
     * 设备Mqtt异常上报
     * @return Json
     */
    public function deviceMqttError(): Json
    {
        if (!$this->apkVerify()) {
            return jsonReturn(0, [], 'Code验证错误');
        }
        //处理设备故障
        $run = DeviceClient::getInstance();
        $run->eventHand($this->imei, 4);
        return jsonReturn(1, []);
    }

    /**
     * 设备安装成功通知
     * @param Request $request
     * @return Json
     */
    public function deviceInstallNotice(Request $request): Json
    {
        $param['mac_id'] = $request::param('mac_id/s', '');
        $param['latitude'] = $request::param('latitude/s', '');
        $param['longitude'] = $request::param('longitude/s', '');
        $param['province'] = $request::param('province/d', 0);
        $param['city'] = $request::param('city/d', 0);
        $param['county'] = $request::param('county/d', 0);
        $param['addr'] = $request::param('addr/s', '');
        $sign = $request::param('sign/s', '');
        if (!$param['mac_id'] or !$sign) {
            return jsonReturn(0, [], 'mac_id或sign参数错误');
        }
        //校验参数
        $verify_sign = arrayDataSignature($param);
        if ($verify_sign != $sign) {
            return jsonReturn(0, [], '签名验证未通过');
        }

        //获取设备模型
        $model = Device::where(['mac_id' => $param['mac_id']])->find();
        if (!$model) {
            return jsonReturn(0, [], '设备不存在');
        }
        //更新数据库
        $param['install'] = 1;
        $param['install_time'] = time();
        $res = $model->save($param);
        //指定取袋路径
        //删除当前设备
        $scan_bag_way = ScanBagWayDevice::where('mac_id',$param['mac_id'])->find();
        $data[]=[
            'key'=>'V2_Way_2_0',
            'mac_id'=>$param['mac_id'],
            'remark'=>$param['addr'],
            'update_time'=>time()
        ];
        if($scan_bag_way){
            if(preg_match('/^V1_*/',$scan_bag_way->key,$result)){
                ScanBagWayDevice::deleteData(['mac_id' => $param['mac_id']], true);
                $model = new ScanBagWayDevice();
                $model->saveAll(array_merge($data));
            }
        }else{
            $model = new ScanBagWayDevice();
            $model->saveAll(array_merge($data));
        }
        if ($res) {
            $res = DeviceClient::commandDown(61, $model->imei, [], '设备安装成功通知');
            return jsonReturn(1, $res);
        }
        return jsonReturn(0, []);
    }

    /**
     * 设备拆除成功通知
     * @param Request $request
     * @return Json
     */
    public function deviceDismantleNotice(Request $request): Json
    {
        $param['mac_id'] = $request::param('mac_id/s', '');
        $sign = $request::param('sign/s', '');
        if (!$param['mac_id'] or !$sign) {
            return jsonReturn(0, [], 'mac_id或sign参数错误');
        }
        //校验参数
        $verify_sign = arrayDataSignature($param);
        if ($verify_sign != $sign) {
            return jsonReturn(0, [], '签名验证未通过');
        }
        //获取设备模型
        $model = Device::where(['mac_id' => $param['mac_id']])->find();
        if (!$model) {
            return jsonReturn(0, []);
        }
        //更新数据库
        $model->install = 2;
        $model->dismant_time = time();
        $res = $model->save();
        if ($res) {
            $res = DeviceClient::commandDown(62, $model->imei, [], '设备拆除成功通知');
            return jsonReturn(1, $res);
        }
        return jsonReturn(0, []);
    }

    /**
     * 设备重启事件
     * @param DeviceService $deviceService
     * @return Json
     */
    public function deviceRestart(Request $request,DeviceService $deviceService): Json
    {
        $imeis = $param['imeis'] = $request::param('imeis/s', []);
        $sign = $request::param('sign/s', '');
        if (!$param['imeis'] or !$sign) {
            return jsonReturn(0, [], 'mac_id或sign参数错误');
        }
        //校验参数
        $verify_sign = arrayDataSignature($param);
        if ($verify_sign != $sign) {
            return jsonReturn(0, [], '签名验证未通过');
        }
        if (!$imeis) {
            return jsonReturn(0, [], '参数错误');
        }
        $imeis =explode(',',$imeis);
        return $deviceService->deviceRestart($imeis);
    }

    /**
     * 音量调整事件
     * @param DeviceService $deviceService
     * @return Json
     */
    public function volumeSet(DeviceService $deviceService): Json
    {
        $imeis =$param['imeis'] = Request::param('imeis/s', []);
        $volume =$param['volume'] = Request::param('volume/d', 0);
        $sign = Request::param('sign/s', '');
        if (!$param['imeis'] or !$sign) {
            return jsonReturn(0, [], 'imeis或sign参数错误');
        }
        //校验参数
        $verify_sign = arrayDataSignature($param);
        if ($verify_sign != $sign) {
            return jsonReturn(0, [], '签名验证未通过');
        }
        if (!$imeis) {
            return jsonReturn(0, [], '参数错误');
        }
        $imeis= explode(',',$imeis);
        return $deviceService->volumeSet($imeis, $volume);
    }

    /**
     * 定时开关机事件
     * @param DeviceService $deviceService
     * @return Json
     */
    public function timingSwitch(DeviceService $deviceService): Json
    {
        $imeis =$param['imeis']= Request::param('imeis/s', []);
        $time_type = Request::param('time_type/d', 1);
        $on_time =$param['on_time']= Request::param('on_time/s', '');
        $off_time =$param['off_time']= Request::param('off_time/s', '');
        $sign =Request::param('sign/s', '');
        if (!$imeis or !$sign) {
            return jsonReturn(0, [], '参数错误');
        }
        //校验参数
        $verify_sign = arrayDataSignature($param);
        if ($verify_sign != $sign) {
            return jsonReturn(0, [], '签名验证未通过');
        }
        $imeis= explode(',',$imeis);
        return $deviceService->timingSwitch($imeis, $time_type, $on_time, $off_time);
    }

    /**
     * 电机出货长度事件
     * @param DeviceService $deviceService
     * @return Json
     */
    public function motorDeliveryLength(DeviceService $deviceService): Json
    {
        $imeis =$param['imeis']= Request::param('imeis/s', []);
        $motor =$param['motor']= Request::param('motor/d', 1);
        $sign =Request::param('sign/s', '');
        if (!$imeis or !$sign) {
            return jsonReturn(0, [], '参数错误');
        }
        //校验参数
        $verify_sign = arrayDataSignature($param);
        if ($verify_sign != $sign) {
            return jsonReturn(0, [], '签名验证未通过');
        }
        $imeis= explode(',',$imeis);
        return $deviceService->motorDeliveryLength($imeis, $motor);
    }

}
